﻿using IdentityManagement.Localization;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Threading.Tasks;
using Xms.Abp.Application.Services;
using Xms.Abp.Data;

namespace IdentityManagement
{
    public class OrganizationUnitAppService :
        XmsCrudAppService<OrganizationUnit, OrganizationUnitResult, Guid, OrganizationUnitPagedParameter, OrganizationUnitCreateParameter, OrganizationUnitUpdateParameter>,
        IOrganizationUnitAppService
    {
        protected IOrganizationUnitRepository OrganizationUnitRepository { get; }

        public OrganizationUnitAppService(IOrganizationUnitRepository repository) : base(repository)
        {
            OrganizationUnitRepository = repository;
            //ObjectMapperContext = typeof(IdentityManagementApplicationModule);
            LocalizationResource = typeof(IdentityResource);
        }

        protected virtual string TreePolicyName => GetPolicy();

        public async Task<Xms.Abp.Application.Dtos.PagedResult<OrganizationUnitTreeResult>> GetTreeAsync(OrganizationUnitTreeFilterParameter parameter)
        {
            await CheckPolicyAsync(TreePolicyName);
            var organizationUnit = await Repository.GetAsync(parameter.Id);
            var root = ObjectMapper.MapTo<OrganizationUnitTreeResult>(organizationUnit);
            var query = (await Repository.AsNoTrackingAsync())
                .Where(r => r.ParentId == parameter.Id)
                .WhereIf(!parameter.Filter.IsNullOrWhiteSpace(), r => r.DisplayName.Contains(parameter.Filter));
            var total = await query.CountAsync();
            if (!parameter.Sorting.IsNullOrWhiteSpace())
            {
                query = query.OrderBy(parameter.Sorting);
            }
            var children = await query
                .Skip(parameter.SkipCount)
                .Take(parameter.MaxResultCount)
                .ToListAsync();
            if (children.Count > 0)
            {
                foreach (var item in children)
                {
                    var child = ObjectMapper.MapTo<OrganizationUnitTreeResult>(organizationUnit);
                    var list = await OrganizationUnitRepository.GetAllChildrenWithParentCodeAsync(item.Code, item.Id);
                    var items = ObjectMapper.MapTo<OrganizationUnitTreeResult>(list).ToTree(r => r.Id, r => r.ParentId).ToList();
                    child.Children = items;
                    root.Children.Add(child);
                }
            }
            return new(total, parameter.MaxResultCount, parameter.SkipCount, new List<OrganizationUnitTreeResult> { root });
        }

        protected override async Task<IQueryable<OrganizationUnit>> CreateFilteredQueryAsync(OrganizationUnitPagedParameter input)
        {
            var query = await base.CreateFilteredQueryAsync(input);
            query = query.WhereIf(!input.Filter.IsNullOrWhiteSpace(), r => r.DisplayName.Contains(input.Filter));
            return query;
        }

        protected override Func<OrganizationUnitCreateParameter, OrganizationUnit> EntityCreator
            => input => new OrganizationUnit(GuidGenerator.Create(), input.No, input.DisplayName, input.ParentId, CurrentTenant.Id);

        public virtual async Task<Xms.Abp.Application.Dtos.PagedResult<OrganizationUnitResult>> PagedByTypeAsync(OrganizationUnitFilterByTypePatameter parameter)
        {
            var query = (await Repository.AsNoTrackingAsync())
                .Where(r => r.ParentId == parameter.ParentId && r.Type == parameter.Type)
                .WhereIf(!parameter.Filter.IsNullOrWhiteSpace(), r => r.DisplayName.Contains(parameter.Filter));
            var total = await query.CountAsync();
            if (!parameter.Sorting.IsNullOrWhiteSpace())
            {
                query = query.OrderBy(parameter.Sorting);
            }
            var list = await query.Skip(parameter.SkipCount).Take(parameter.MaxResultCount).ToListAsync();
            var items = ObjectMapper.MapTo<OrganizationUnitResult>(list);
            return new(total, parameter.MaxResultCount, parameter.SkipCount, items);
        }
    }
}
